﻿using System;
using System.Runtime.InteropServices;
using System.Windows.Media;
using DotNetImage.Util;

namespace DotNetImage.Imaging
{
    public enum ColorIndex
    {
        NOCOLOR = 0,
        BLUE = 0,
        GREEN,
        RED,
        ALPHA
    }



    /// <summary>
    /// Container for pixel data. Callers don't have a direct access to the byte array in DotNetImage class.
    /// The only way is to work through GetPixel / SetPixel methods.
    /// </summary>
    /// <typeparam name="TPixel">The type representing the full pixel. UInt32 for 32 BGRA or byte for 8bpp grayscale</typeparam>
    /// <typeparam name="TColorChannel">The type representing the color in the pixel. byte for 32 BGRA or short for 16bpp grayscale</typeparam>
    [StructLayout(LayoutKind.Explicit)]
    public class DotNetPixel<TPixel, TColorChannel> 
        where TPixel : struct,
                      IComparable, 
                      IComparable<TPixel>, 
                      IConvertible, 
                      IEquatable<TPixel>, 
                      IFormattable
        where TColorChannel : struct,
                      IComparable,
                      IComparable<TColorChannel>, 
                      IConvertible,
                      IEquatable<TColorChannel>, 
                      IFormattable
    {
        public TColorChannel[] ColorChannels { get; private set; }

        public bool IsMonochrome { get; private set; }

        
        /// <summary>
        /// Receives array of at least 1 byte color channels storage
        /// </summary>
        /// <param name="data"></param>
        public DotNetPixel(TColorChannel[] data)
        {
            IsMonochrome = (data.Length == 1);
            ColorChannels = data;
        }

        public TColorChannel GetColor(ColorIndex colorIndex)
        {
            return ColorChannels[(int)colorIndex];
        }


        public DotNetPixel(TPixel data)
        {
            int sizeOfPixel = TypeHelper.SizeOf(typeof(TPixel));
            int sizeOfColor = TypeHelper.SizeOf(typeof(TColorChannel));
            IsMonochrome = (sizeOfPixel == sizeOfColor);
            ColorChannels = new TColorChannel[(IsMonochrome ? 1 : 4)];

            if (IsMonochrome)
            {
                ColorChannels[0] = data;
            }
            else
            {
                // TODO: How to split data onto 4 equal parts?
            }
        }

        public void SetBGR(uint blue, uint green, uint red)
        {
            if (IsMonochrome)
            {
                throw new Unsu
            }
            this.Blue = CheckBorders(blue);
            this.Red = CheckBorders(red);
            this.Green = CheckBorders(green);
        }

        public void AddBGR(int blue, int green, int red)
        {
            this.Blue = (byte)CheckBorders(blue + Blue);
            this.Red = (byte)CheckBorders(red + Red);
            this.Green = (byte)CheckBorders(green + Green);
        }








        public static DotNetPixel<TPixel, TColorChannel> operator +(DotNetPixel<TPixel, TColorChannel> pixLeft, DotNetPixel<TPixel, TColorChannel> pixRight)
        {
            int blue = pixLeft.Blue + pixRight.Blue;
            int green = pixLeft.Green + pixRight.Green;
            int red = pixLeft.Red + pixRight.Red;
            int alpha = pixLeft.Alpha + pixRight.Alpha;

            DotNetPixel<TPixel, TColorChannel> result = new DotNetPixel<TPixel, TColorChannel>();
            result.Blue = CheckBorders(blue);
            result.Green = CheckBorders(green);
            result.Red = CheckBorders(red);
            result.Alpha = CheckBorders(alpha);
            return result;
        }

        public static DotNetPixel<TPixel, TColorChannel> operator -(DotNetPixel<TPixel, TColorChannel> pixLeft, DotNetPixel<TPixel, TColorChannel> pixRight)
        {
            int blue = Math.Abs(pixLeft.Blue - pixRight.Blue);
            int green = Math.Abs(pixLeft.Green - pixRight.Green);
            int red = Math.Abs(pixLeft.Red - pixRight.Red);
            int alpha = Math.Abs(pixLeft.Alpha - pixRight.Alpha);

            DotNetPixel<TPixel, TColorChannel> result = new DotNetPixel<TPixel, TColorChannel>();
            result.Blue = CheckBorders(blue);
            result.Green = CheckBorders(green);
            result.Red = CheckBorders(red);
            result.Alpha = CheckBorders(alpha);
            return result;
        }

    }
}
